#pragma once

#include "RdcBuffer.h"
#include "ServerChannelCoreImpl.h"
#include <exception>

#include <boost/thread.hpp>
#include <boost/bind.hpp>

namespace rdc_transport
{
    struct IReader;
    struct IReadHandler;

    class ServerReadWithProtocol
    {
    public:
        ServerReadWithProtocol(IReader* internalRead);
        void Read(Buffer* buffer);

    private:
        IReader* internalRead_;
    };

    class ServerReadNoProtocol
    {
    public:
        ServerReadNoProtocol(IReader* internalRead);
        void Read(Buffer* buffer);

    private:
        IReader* internalRead_;
        DWORD m_dwReadBufferRemainder;
        CHAR m_pReadBuffer[CHANNEL_CHUNK_LENGTH];
    };

    template<class ReadAlgorithm>
    class ServerReadStrategy
    {
    public:
        ServerReadStrategy(IReader* internalRead)
            : rh_(NULL)
            , internalRead_(internalRead)
        {}

        ~ServerReadStrategy()
        {
            if (worker_.get())
            {
                worker_->join();
            }
        }

        void Worker()
        {
            //Buffer buffer;

            bool process = true;
            while (process)
            {
                try
                {
                    Buffer buffer;
                    //
                    internalRead_.Read(&buffer);
                    rh_->OnRead(&buffer);
                }
                catch(termination_notification&)
                {
                    process = false;
                }
                catch(std::exception& ex)
                {
                    rh_->OnReadFail(ex.what());
                    process = false;
                }
            }
        }

        void SetReadHandler(IReadHandler* rh)
        {
            assert(rh);
            rh_ = rh;
            worker_.reset(new boost::thread(&ServerReadStrategy<ReadAlgorithm>::Worker, this));
        }

        void OnReconnect()
        {
            worker_.reset(new boost::thread(&ServerReadStrategy<ReadAlgorithm>::Worker, this));
        }

    private:
        ReadAlgorithm internalRead_;
        IReadHandler* rh_;

        std::auto_ptr<boost::thread> worker_;
    };
}